package com.jason.www.code.redis;

import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.BulkMapper;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.HyperLogLogOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.query.SortQuery;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.core.script.ScriptExecutor;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * SpringRedisTemplateAdapter  通过维护一个自定义getTemplate()对象  OverRide所有RedisTemplate所有方法通过getTemplate()来调用
 * @param <K>
 * @param <V>
 */
public class SpringRedisTemplateAdapter<K,V> extends RedisTemplate<K,V> {
    private ThreadLocal<RedisTemplate<K, V>> localTemplate = new ThreadLocal<RedisTemplate<K, V>>();
    private RedisConnectionFactory connectionFactory;
    private RedisSerializer<?> defaultSerailizer = new JdkSerializationRedisSerializer();
    private boolean enableDefaultSerializer = false;
    private boolean enableTransactionSupport = false;
    private boolean exposeConnection = false;
    private RedisSerializer<?> hashKeySerializer;
    private RedisSerializer<?> hashValueSerializer;
    private RedisSerializer<?> keySerializer;
    private ScriptExecutor<K> scriptExecutor;
    private RedisSerializer<String> stringSerializer = new StringRedisSerializer();
    private RedisSerializer<?> valueSerializer;

    public SpringRedisTemplateAdapter() {
    }

    private RedisTemplate<K, V> getTemplate() {
        RedisTemplate<K, V> temp = localTemplate.get();
        if(temp == null){
            temp = new RedisTemplate<K, V>();
            temp.setConnectionFactory(this.connectionFactory);
            temp.setDefaultSerializer(this.defaultSerailizer);
            temp.setEnableDefaultSerializer(this.enableDefaultSerializer);
            temp.setEnableTransactionSupport(this.enableTransactionSupport);
            temp.setExposeConnection(this.exposeConnection);
            temp.setHashKeySerializer(this.hashKeySerializer);
            temp.setHashValueSerializer(this.hashValueSerializer);
            temp.setKeySerializer(this.keySerializer);
            temp.setScriptExecutor(this.scriptExecutor);
            temp.setStringSerializer(this.stringSerializer);
            temp.setValueSerializer(this.valueSerializer);
            temp.afterPropertiesSet();
            localTemplate.set(temp);
        }
        return temp;
    }

    @Override
    public void afterPropertiesSet() {
        super.afterPropertiesSet();
    }

    @Override
    public <T> T execute(RedisCallback<T> action) {
        return getTemplate().execute(action);
    }

    @Override
    public <T> T execute(RedisCallback<T> action, boolean exposeConnection) {
        return getTemplate().execute(action, exposeConnection);
    }

    @Override
    public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
        return getTemplate().execute(action, exposeConnection, pipeline);
    }

    @Override
    public <T> T execute(SessionCallback<T> session) {
        return getTemplate().execute(session);
    }

    @Override
    public List<Object> executePipelined(SessionCallback<?> session) {
        return getTemplate().executePipelined(session);
    }

    @Override
    public List<Object> executePipelined(SessionCallback<?> session, RedisSerializer<?> resultSerializer) {
        return getTemplate().executePipelined(session, resultSerializer);
    }

    @Override
    public List<Object> executePipelined(RedisCallback<?> action) {
        return getTemplate().executePipelined(action);
    }

    @Override
    public List<Object> executePipelined(RedisCallback<?> action, RedisSerializer<?> resultSerializer) {
        return getTemplate().executePipelined(action, resultSerializer);
    }

    @Override
    public <T> T execute(RedisScript<T> script, List<K> keys, Object... args) {
        return getTemplate().execute(script, keys, args);
    }

    @Override
    public <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSerializer<T> resultSerializer, List<K> keys, Object... args) {
        return getTemplate().execute(script, argsSerializer, resultSerializer, keys, args);
    }

    @Override
    public boolean isExposeConnection() {
        return getTemplate().isExposeConnection();
    }

    @Override
    public void setExposeConnection(boolean exposeConnection) {
        this.exposeConnection = exposeConnection;
    }

    @Override
    public boolean isEnableDefaultSerializer() {
        return getTemplate().isEnableDefaultSerializer();
    }

    @Override
    public void setEnableDefaultSerializer(boolean enableDefaultSerializer) {
        this.enableDefaultSerializer = enableDefaultSerializer;
    }

    @Override
    public RedisSerializer<?> getDefaultSerializer() {
        return getTemplate().getDefaultSerializer();
    }

    @Override
    public void setDefaultSerializer(RedisSerializer<?> serializer) {
        this.defaultSerailizer  = defaultSerailizer;
    }

    @Override
    public void setKeySerializer(RedisSerializer<?> serializer) {
        this.keySerializer = keySerializer;
    }

    @Override
    public RedisSerializer<?> getKeySerializer() {
        return getTemplate().getKeySerializer();
    }

    @Override
    public void setValueSerializer(RedisSerializer<?> serializer) {
        this.valueSerializer = valueSerializer;
    }

    @Override
    public RedisSerializer<?> getValueSerializer() {
        return getTemplate().getValueSerializer();
    }

    @Override
    public RedisSerializer<?> getHashKeySerializer() {
        return getTemplate().getHashKeySerializer();
    }

    @Override
    public void setHashKeySerializer(RedisSerializer<?> hashKeySerializer) {
        this.hashKeySerializer = hashKeySerializer;
    }

    @Override
    public RedisSerializer<?> getHashValueSerializer() {
        return getTemplate().getHashValueSerializer();
    }

    @Override
    public void setHashValueSerializer(RedisSerializer<?> hashValueSerializer) {
        this.hashKeySerializer = hashValueSerializer;
    }

    @Override
    public RedisSerializer<String> getStringSerializer() {
        return getTemplate().getStringSerializer();
    }

    @Override
    public void setStringSerializer(RedisSerializer<String> stringSerializer) {
        this.stringSerializer = stringSerializer;
    }

    @Override
    public void setScriptExecutor(ScriptExecutor<K> scriptExecutor) {
        this.scriptExecutor = scriptExecutor;
    }

    @Override
    public List<Object> exec() {
        return getTemplate().exec();
    }

    @Override
    public List<Object> exec(RedisSerializer<?> valueSerializer) {
        return getTemplate().exec(valueSerializer);
    }

    @Override
    public void delete(K key) {
        getTemplate().delete(key);
    }

    @Override
    public void delete(Collection<K> keys) {
        getTemplate().delete(keys);
    }

    @Override
    public Boolean hasKey(K key) {
        return getTemplate().hasKey(key);
    }

    @Override
    public Boolean expire(K key, long timeout, TimeUnit unit) {
        return getTemplate().expire(key, timeout, unit);
    }

    @Override
    public Boolean expireAt(K key, Date date) {
        return getTemplate().expireAt(key, date);
    }

    @Override
    public void convertAndSend(String channel, Object message) {
        getTemplate().convertAndSend(channel, message);
    }

    @Override
    public Long getExpire(K key) {
        return getTemplate().getExpire(key);
    }

    @Override
    public Long getExpire(K key, TimeUnit timeUnit) {
        return getTemplate().getExpire(key, timeUnit);
    }

    @Override
    public Set<K> keys(K pattern) {
        return getTemplate().keys(pattern);
    }

    @Override
    public Boolean persist(K key) {
        return getTemplate().persist(key);
    }

    @Override
    public Boolean move(K key, int dbIndex) {
        return getTemplate().move(key, dbIndex);
    }

    @Override
    public K randomKey() {
        return getTemplate().randomKey();
    }

    @Override
    public void rename(K oldKey, K newKey) {
        getTemplate().rename(oldKey, newKey);
    }

    @Override
    public Boolean renameIfAbsent(K oldKey, K newKey) {
        return getTemplate().renameIfAbsent(oldKey, newKey);
    }

    @Override
    public DataType type(K key) {
        return getTemplate().type(key);
    }

    @Override
    public byte[] dump(K key) {
        return getTemplate().dump(key);
    }

    @Override
    public void restore(K key, byte[] value, long timeToLive, TimeUnit unit) {
        getTemplate().restore(key, value, timeToLive, unit);
    }

    @Override
    public void multi() {
        getTemplate().multi();
    }

    @Override
    public void discard() {
        getTemplate().discard();
    }

    @Override
    public void watch(K key) {
        getTemplate().watch(key);
    }

    @Override
    public void watch(Collection<K> keys) {
        getTemplate().watch(keys);
    }

    @Override
    public void unwatch() {
        getTemplate().unwatch();
    }

    @Override
    public List<V> sort(SortQuery<K> query) {
        return getTemplate().sort(query);
    }

    @Override
    public <T> List<T> sort(SortQuery<K> query, RedisSerializer<T> resultSerializer) {
        return getTemplate().sort(query, resultSerializer);
    }

    @Override
    public <T> List<T> sort(SortQuery<K> query, BulkMapper<T, V> bulkMapper) {
        return getTemplate().sort(query, bulkMapper);
    }

    @Override
    public <T, S> List<T> sort(SortQuery<K> query, BulkMapper<T, S> bulkMapper, RedisSerializer<S> resultSerializer) {
        return getTemplate().sort(query, bulkMapper, resultSerializer);
    }

    @Override
    public Long sort(SortQuery<K> query, K storeKey) {
        return getTemplate().sort(query, storeKey);
    }

    @Override
    public BoundValueOperations<K, V> boundValueOps(K key) {
        return getTemplate().boundValueOps(key);
    }

    @Override
    public ValueOperations<K, V> opsForValue() {
        return getTemplate().opsForValue();
    }

    @Override
    public ListOperations<K, V> opsForList() {
        return getTemplate().opsForList();
    }

    @Override
    public BoundListOperations<K, V> boundListOps(K key) {
        return getTemplate().boundListOps(key);
    }

    @Override
    public BoundSetOperations<K, V> boundSetOps(K key) {
        return getTemplate().boundSetOps(key);
    }

    @Override
    public SetOperations<K, V> opsForSet() {
        return getTemplate().opsForSet();
    }

    @Override
    public BoundZSetOperations<K, V> boundZSetOps(K key) {
        return getTemplate().boundZSetOps(key);
    }

    @Override
    public ZSetOperations<K, V> opsForZSet() {
        return getTemplate().opsForZSet();
    }

    @Override
    public HyperLogLogOperations<K, V> opsForHyperLogLog() {
        return getTemplate().opsForHyperLogLog();
    }

    @Override
    public <HK, HV> BoundHashOperations<K, HK, HV> boundHashOps(K key) {
        return getTemplate().boundHashOps(key);
    }

    @Override
    public <HK, HV> HashOperations<K, HK, HV> opsForHash() {
        return getTemplate().opsForHash();
    }

    @Override
    public void killClient(String host, int port) {
        getTemplate().killClient(host, port);
    }

    @Override
    public List<RedisClientInfo> getClientList() {
        return getTemplate().getClientList();
    }

    @Override
    public void slaveOf(String host, int port) {
        getTemplate().slaveOf(host, port);
    }

    @Override
    public void slaveOfNoOne() {
        getTemplate().slaveOfNoOne();
    }

    @Override
    public void setEnableTransactionSupport(boolean enableTransactionSupport) {
        getTemplate().setEnableTransactionSupport(enableTransactionSupport);
    }

    @Override
    public RedisConnectionFactory getConnectionFactory() {
        return getTemplate().getConnectionFactory();
    }

    @Override
    public void setConnectionFactory(RedisConnectionFactory connectionFactory) {
        this.connectionFactory = connectionFactory;
    }


}
